//
//  AppDelegate.m
//  MyChat
//
//  Created by Ansen on 15-1-29.
//  Copyright (c) 2015年 Ansen. All rights reserved.
//

#import "AppDelegate.h"
#import "LoginUser.h"
#import "NSString+Helper.h"

@interface AppDelegate ()<XMPPStreamDelegate,XMPPRosterDelegate>
{
    CompletionBlock _completionBlock; // 成功的块代码
    CompletionBlock _failBlock;       // 失败的块代码
    
    XMPPReconnect *_xmppReconnect;    // XMPP重新连接XMPPStream
    XMPPvCardCoreDataStorage *_xmppvCardStorage; // 电子名片的数据存储模块
    
    XMPPCapabilities *_xmppCapabilities;    // 实体扩展模块
    XMPPCapabilitiesCoreDataStorage *_xmppCapabilitiesCoreDataStorage;   // 数据存储模块
    
}
@end

@implementation AppDelegate

#pragma mark 根据用户登录状态加载对应的Storyboard显示
-(void)showStoryboardWithLogonState:(BOOL)isUserLogon
{
    UIStoryboard *storyboard = nil;
    
    if (isUserLogon) {
        // 显示Login.sotryboard
        storyboard = [UIStoryboard storyboardWithName:@"Login" bundle:nil];
           }else{
        // 显示Main.storyboard
        storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    }
    
    // 在主线程队列负责切换Storyboard，而不影响后台代理的数据处理
    dispatch_async(dispatch_get_main_queue(), ^{
        // 如果在项目属性中，没有指定主界面（启动的Storyboard，self.window不会被实例化）
        // 把Storyboard的初始视图控制器设置为window的rootViewController
        [self.window setRootViewController:storyboard.instantiateInitialViewController];
        
        if (!self.window.isKeyWindow) {
            [self.window makeKeyAndVisible];
        }
    });
    
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // 1. 实例化window
//    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

    // 2. 设置XMPPStream
    [self setupStream];
    
    return YES;
}
							
- (void)applicationWillResignActive:(UIApplication *)application
{
//    [self disConnect];
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // 应用程序被激活后，直接连接，使用系统偏好中的保存的用户记录登录
    // 从而实现自动登录的效果！
    [self connect];
}

-(void)dealloc
{
    // 释放XMPP相关对象及扩展模块
    [self teardownStream];
}

#pragma mark - XMPP相关方法
#pragma mark 设置XMPPStream
-(void)setupStream
{
    // 0. 方法被调用时，要求_xmppStream必须为nil。否则通过断言提示程序员，并终止程序运行！
    NSAssert(_xmppStream == nil, @"XMPPStram被多次实例化!");
    
    // 1. 实例化XMPPStream
    _xmppStream = [[XMPPStream alloc] init];
    
    // 让XMPP在真机运行时支持后台，在模拟器上是不支持后台服务运行的
    #if !TARGET_IPHONE_SIMULATOR
    {
        //允许XMPPStream在真机运行时，支持后台网络通讯！
        [_xmppStream setEnableBackgroundingOnSocket:YES];
    }
    #endif
    
    // 2. 扩张模块
    // 2.1 重新连接模块
    _xmppReconnect = [[XMPPReconnect alloc] init];
    
    // 2.2 电子名片模块
    _xmppvCardStorage = [XMPPvCardCoreDataStorage sharedInstance];
    _xmppvCardModule = [[XMPPvCardTempModule alloc] initWithvCardStorage:_xmppvCardStorage];
    _xmppvCardAvatarModule = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:_xmppvCardModule];
    
    // 2.3 花名册模块
    _xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
    _xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:_xmppRosterStorage];
    // 设置自动接收好友订阅请求
    [_xmppRoster setAutoAcceptKnownPresenceSubscriptionRequests:YES];
    //自动从服务器更新好友记录，例如：好友自己更改了名片
    [_xmppRoster setAutoFetchRoster:YES];
    
    // 2.5 实体扩展模块(增加网络传输速度-图片)
    _xmppCapabilitiesCoreDataStorage = [[XMPPCapabilitiesCoreDataStorage alloc] init];
    _xmppCapabilities = [[XMPPCapabilities alloc] initWithCapabilitiesStorage:_xmppCapabilitiesCoreDataStorage];
    
    // 2.6 消息归档模块
    _xmppMessageArchivingCoreDataStorage = [[XMPPMessageArchivingCoreDataStorage alloc] init];
    _xmppMessageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:_xmppMessageArchivingCoreDataStorage];
    
    
    // 3. 将重新连接模块添加到XMPPStream
    [_xmppReconnect activate:_xmppStream];
    [_xmppvCardModule activate:_xmppStream];
    [_xmppvCardAvatarModule activate:_xmppStream];
    [_xmppRoster activate:_xmppStream];
    [_xmppCapabilities activate:_xmppStream];
    [_xmppMessageArchiving activate:_xmppStream];
    
    // 4. 添加代理
    // 因为所有网络请求都是做基于网络的数据处理，跟界面UI无关，因此可以让代理方法在其他线城中执行
    // 从而提高程序的运行性能
//    [_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
//    [_xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
    
    [_xmppStream addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
    [_xmppRoster addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
 }

// 销毁XMPPStram并注销已注册的扩展模块
-(void)teardownStream
{
    // 1. 删除代理
    [_xmppStream removeDelegate:self];
    [_xmppRoster removeDelegate:self];
    
    // 2. 取消激活在setupStream方法中激活的扩展模块
    [_xmppReconnect deactivate];
    [_xmppvCardModule deactivate];
    [_xmppvCardAvatarModule deactivate];
    [_xmppRoster deactivate];
    [_xmppCapabilities deactivate];
    [_xmppMessageArchiving deactivate];
    
    // 3. 断开XMMPPStream的连接
    [_xmppStream disconnect];
    
    // 4. 内存清理
    _xmppStream = nil;
    _xmppReconnect = nil;
    _xmppvCardModule = nil;
    _xmppvCardStorage = nil;
    _xmppvCardAvatarModule = nil;
    _xmppRoster = nil;
    _xmppRosterStorage = nil;
    _xmppCapabilities = nil;
    _xmppCapabilitiesCoreDataStorage = nil;
    _xmppMessageArchivingCoreDataStorage = nil;
    _xmppMessageArchiving = nil;
}

#pragma mark 连接到服务器
-(void)connect
{
     // 1. 如果XMPPStream当前已经连接，直接返回
    if ([_xmppStream isConnected]) {
        return;
    }
    
    //    在C语言中if判断真假：非零即真，如果_xmppStream==nil下面这段代码，与上面的代码结果不同。
    //    if (![_xmppStream isDisconnected]) {
    //        return;
    //    }
    
    // 2.指定用户名、主机（服务器），连接时不需要password
    NSString *hostName = Login_User.hostName;
    NSString *JIDName = Login_User.myJIDName;
    
    if ([hostName isEmptyString] || [JIDName isEmptyString]) {
        [self showStoryboardWithLogonState:YES];
        
        return;
    }
    
    // 3.设置XMPPStream的JID和主机
    [_xmppStream setMyJID:[XMPPJID jidWithString:JIDName]];
    [_xmppStream setHostName:hostName];
    
    //4. 开始连接,因为是在局域网所以设置这个XMPPStreamTimeoutNone，一般设置5秒
    NSError *error = nil;
    [_xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&error];
    
    // 提示：如果没有指定JID和hostName，才会出错，其他都不出错。
    if (error) {
        NSLog(@"连接请求发送出错 - %@", error.localizedDescription);
    }else{
        NSLog(@"连接请求发送成功！");
    }
}

#pragma mark 连接到服务器
-(void)connectWithCompletion:(CompletionBlock)completion falied:(CompletionBlock)failied
{
    // 1. 记录块代码
    _completionBlock = completion;
    _failBlock = failied;
    
    // 2. 如果已经存在连接，先断开连接，然后再次连接
    if ([_xmppStream isConnected]) {
        [_xmppStream disconnect];
    }
    
    // 3. 连接到服务器
    [self connect];
}

#pragma mark 断开连接
-(void)disConnect
{
    // 1. 通知服务器下线
    [self goOffline];
    // 2. XMPPStream断开连接
    [_xmppStream disconnect];//进入后台后会刷新花名册
}

-(void)logout
{
    // 1. 通知服务器下线，并断开连接
    [self disConnect];
    
    // 2. 显示用户登录Storyboard
    [self showStoryboardWithLogonState:YES];

}

#pragma mark 通知服务器用户下线
-(void)goOnline
{
    // 1. 实例化一个”展现“，上线的报告
    XMPPPresence *presence = [XMPPPresence presence];
    // 2. 发送Presence给服务器
    // 服务器知道“我”上线后，只需要通知我的好友，而无需通知我，因此，此方法没有回调
    [_xmppStream sendElement:presence];
}

#pragma mark 通知服务器用户下线
- (void)goOffline
{
    NSLog(@"用户下线");
    // 1. 实例化一个”展现“，下线的报告
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
    // 2. 发送Presence给服务器，通知服务器客户端下线
    [_xmppStream sendElement:presence];
}

#pragma mark - 代理方法
#pragma mark 连接完成（如果服务器地址不对，就不会调用此方法）
-(void)xmppStreamDidConnect:(XMPPStream *)sender
{
    NSLog(@"连接建立");
    NSString *password = Login_User.password;
    
    if(_isRegisterUser){
        // 用户注册，发送注册请求
        [_xmppStream registerWithPassword:password error:nil];
    }else{
        [_xmppStream authenticateWithPassword:password error:nil];
    }
}
#pragma mark 注册成功
-(void)xmppStreamDidRegister:(XMPPStream *)sender
{
     NSLog(@"注册成功");
    _isRegisterUser = NO;
    
    // 注册成功，直接发送验证身份请求，从而触发后续的操作
    [_xmppStream authenticateWithPassword:Login_User.password error:nil];
}

#pragma mark 注册失败(用户名已经存在)
-(void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error
{
    NSLog(@"注册失败");
    _isRegisterUser = YES;
    if (_failBlock != nil) {
        dispatch_async(dispatch_get_main_queue(), ^{
            _failBlock();
        });
//        _failBlock();
    }
}
#pragma mark 身份验证通过
-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{

    NSLog(@"身份验证通过");
    if (_completionBlock != nil) {
        dispatch_async(dispatch_get_main_queue(), ^{
            _completionBlock();
        });
//        _completionBlock();
    }
    
    [self goOnline];
    
    // 显示主Storyboard
    [self showStoryboardWithLogonState:NO];
}

#pragma mark 密码错误，身份验证失败
-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error
{
    NSLog(@"身份验证失败");
    if (_failBlock != nil) {
        dispatch_async(dispatch_get_main_queue(), ^{
            _failBlock();
        });
//        _failBlock();
    }
    
    // 显示用户登录Storyboard
    [self showStoryboardWithLogonState:YES];
}

#pragma mark 用户展现变化
-(void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
//    NSLog(@"接收到用户展现数据 - %@", presence);
     // 1. 判断接收到的presence类型是否为subscribe
    if ([presence.type isEqualToString:@"subscribe"]) {
        
        // 2. 取出presence中的from的jid
        XMPPJID *from = [presence from];
        
        // 3. 接受来自from添加好友的订阅请求
        [_xmppRoster acceptPresenceSubscriptionRequestFrom:from andAddToRoster:YES];
    }
}

#pragma mark 接收消息
-(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
//     NSLog(@"接收到用户消息 - %@", message);
}

#pragma mark - XMPPRoster代理
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
{
//    NSLog(@"接收到其他用户的请求 %@", presence);
}

@end
